package com.blq.common.utils.redis;

import com.beust.jcommander.internal.Lists;
import com.blq.common.utils.ResultMsg;
import com.blq.common.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * 防止表单重复提交
 *
 * @Author by Blq
 */
@Slf4j
@Aspect
@Configuration
public class RedisLockMethodInterceptor {
    @Value("${spring.profiles.active}")
    private String springProfilesActive;
    @Value("${spring.application.name}")
    private String springApplicationName;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Pointcut("@annotation(com.blq.common.utils.redis.RedisLock)")
    public void point() {
    }

    @Around("point()")
    public Object doaround(ProceedingJoinPoint joinPoint) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RedisLock localLock = method.getAnnotation(RedisLock.class);
        SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0,0);
        try {
            String lockUniqueKey = String.valueOf(idWorker.nextId());

            Integer expire = localLock.expire();
            if (expire < 0) {
                expire = 5;
            }
            ArrayList<String> keys = (ArrayList<String>) Lists.newArrayList(lockUniqueKey);
            String result = stringRedisTemplate.execute(setNxWithExpireTime, keys, expire.toString());
            if (!"ok".equalsIgnoreCase(result)) {//不存在
                return  ResultMsg.OBJECT_ERROR.setNewData("禁止重复提交");
            }
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable.getMessage());
        }
    }

    /**
     * lua脚本
     */
    private RedisScript<String> setNxWithExpireTime = new DefaultRedisScript<>(
            "return redis.call('set', KEYS[1], 1, 'ex', ARGV[1], 'nx');",
            String.class
    );
}
